// lib/controllers/device_manager_controller.dart
import 'dart:async';

import 'package:get/get.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

import '../services/ble/ble_device_service.dart';
import '../pages/widgets/temp_chart.dart'; // 引入 TempPoint

class DeviceManagerController extends GetxController {
  final ble = BLEDeviceService();

  // 扫描到的设备列表
  final devices = <ScanResult>[].obs;

  // 当前连接设备 ID（字符串）
  final connectedId = ''.obs;

  // 当前连接的 BluetoothDevice
  BluetoothDevice? connectedDevice;

  // ========= 温度 & 状态 =========
  /// 当前温度（内部统一存储为摄氏度 °C，UI 显示时按 isCelsius 转换）
  final currentTemp = 0.0.obs;

  /// 设定温度（单位：与设备当前模式一致，isCelsius = true 表示 °C，false 表示 °F）
  final targetTemp = 60.0.obs;

  /// 是否使用摄氏度（true=°C / false=°F）
  final isCelsius = true.obs;

  /// 设定时间（分钟）
  final targetTime = 20.obs;

  /// 开关机状态
  final powerOn = false.obs;

  /// 内灯 / 外灯 / 彩灯 / 臭氧 / 负离子 / 红光
  final innerLight = false.obs;
  final outerLight = false.obs;
  final colorLight = false.obs;
  final ozone = false.obs;
  final anion = false.obs;
  final redLight = false.obs;

  /// 功率档位：1=100%，2=75%，3=50%
  final powerRatio = 1.obs;

  /// 心率（rpm）
  final heartRate = 0.obs;

  /// 最近一条原始回包日志（给 UI 显示用）
  final lastPacket = ''.obs;

  /// 温度历史（最近 60 秒，内部仍然用 °C）
  final tempHistory = <TempPoint>[].obs;

  // 温度范围（协议限制）
  static const double _minC = 25.0;
  static const double _maxC = 65.0;
  static const double _minF = 77.0;
  static const double _maxF = 149.0;

  // 内部订阅 & 定时器
  StreamSubscription? _pktSub;
  Timer? _tempTimer;

  @override
  void onInit() {
    super.onInit();

    print('📡 [DM] scanStream 监听已启动');

    // 监听扫描结果
    ble.scanStream.listen((list) {
      devices.assignAll(list);
      print('📋 [DM] UI更新设备数量: ${devices.length}');
    });

    // 监听协议回包（温度 & 状态等）
    _pktSub = ble.onPacket.listen(_handlePacket);
  }

  // ================================
  // 工具：温度换算
  // ================================
  double _cToF(double c) => c * 9.0 / 5.0 + 32.0;

  double _fToC(double f) => (f - 32.0) * 5.0 / 9.0;

  double clampC(double c) => c.clamp(_minC, _maxC);
  double clampF(double f) => f.clamp(_minF, _maxF);

  // ================================
  // 扫描
  // ================================
  Future<void> startScan() async {
    print('🚀 [DM] 开始扫描蓝牙设备...');
    devices.clear();
    await ble.startScan(seconds: 15);
  }

  Future<void> stopScan() async {
    print('🛑 [DM] 停止扫描');
    await ble.stopScan();
  }

  // ================================
  // 连接
  // ================================
  Future<void> connectTo(ScanResult r) async {
    final id = r.device.remoteId.str;

    // 防重复连接
    if (connectedId.value == id) {
      print('⚠️ 已连接，无需重复连接: $id');
      return;
    }

    print('🔗 [DM] 尝试连接设备: ${r.device.platformName} ($id)');

    await stopScan(); // 避免扫描干扰连接
    await ble.connect(id);

    connectedDevice = r.device;
    connectedId.value = id;

    print('✅ [DM] 已连接设备: $id');

    // 启动温度轮询心跳
    _startTempTimer();

    // 刚连上时，主动拉一遍状态
    _queryAllStatus();

    // 自动跳转主页
    Get.offAllNamed('/main');
  }

  // ================================
  // 断开连接
  // ================================
  Future<void> disconnect() async {
    print('🔌 [DM] 断开连接');

    await ble.disconnect();
    connectedDevice = null;
    connectedId.value = '';

    _stopTempTimer();
  }

  // ================================
  // 对外暴露：主动查询一次全部关键状态
  // ================================
  Future<void> queryAllStatusOnce() async {
    await _queryAllStatus();
  }

  Future<void> _queryAllStatus() async {
    try {
      await ble.cmdQueryTempAndState(); // 实际温度 & 状态
      await ble.cmdQueryTargetTemp();   // 设定温度（0x24 / 0xA4）
      await ble.cmdQueryTargetTime();   // 设定时间
      await ble.cmdQueryInnerLight();   // 内灯状态
      await ble.cmdQueryOuterLight();   // 外灯状态
      await ble.cmdQueryColorLight();   // 彩灯状态
      // 如有需要可继续补：功率比、臭氧、负离子、红光等
    } catch (e) {
      print('⚠️ [DM] 主动查询状态异常: $e');
    }
  }

  // ================================
  // 处理回包
  // ================================
  void _handlePacket(ProtocolPacket p) {
    // 记录原始回包字符串（十六进制）
    final h = p.head.toRadixString(16).padLeft(2, '0');
    final id = p.id.toRadixString(16).padLeft(2, '0');
    final d1 = p.d1.toRadixString(16).padLeft(2, '0');
    final d2 = p.d2.toRadixString(16).padLeft(2, '0');
    final d3 = p.d3.toRadixString(16).padLeft(2, '0');
    final ck = p.checksum.toRadixString(16).padLeft(2, '0');

    lastPacket.value = 'H=$h ID=$id D=$d1 $d2 $d3 CK=$ck';

    // 只关心从设备来的 0xAB 帧
    if (p.head != 0xAB) return;

    switch (p.id) {
      case 0x01: // 开关机状态
        powerOn.value = (p.d1 == 0x31);
        break;

      case 0x02: // 实际温度 + 状态
        _parseTempPacket(p);
        break;

      case 0x03: // 内灯 开关
      case 0x04: // 内灯 状态
        innerLight.value = (p.d1 == 0x31);
        break;

      case 0x06: // 外灯 开关
      case 0x07: // 外灯 状态
        outerLight.value = (p.d1 == 0x31);
        break;

      case 0x09: // 彩灯 状态
      case 0x0A: // 彩灯 开关
        colorLight.value = (p.d1 == 0x31);
        break;

      case 0x0E: // 臭氧
        ozone.value = (p.d1 == 0x31);
        break;

      case 0x0F: // 负离子
        anion.value = (p.d1 == 0x31);
        break;

      case 0x11: // 心率
        final hr = _parseAsciiInt([p.d1, p.d2, p.d3]);
        if (hr != null) {
          heartRate.value = hr;
        }
        break;

      case 0x12: // 功率比
        if (p.d1 >= 0x31 && p.d1 <= 0x33) {
          powerRatio.value = p.d1 - 0x30; // 0x31->1, 0x32->2, 0x33->3
        }
        break;

      case 0x13: // 红光
        redLight.value = (p.d1 == 0x31);
        break;

    // 设定温度（直接返回 0x22 / 0x23）
      case 0x22: // 摄氏设定温度
      case 0x23: // 华氏设定温度
        final t = _parseAsciiDouble([p.d1, p.d2, p.d3]);
        if (t != null) {
          targetTemp.value = t;
          isCelsius.value = (p.id == 0x22);
        }
        break;

    // 获取设定温度（0x24 / 0xA4）
      case 0x24: // 摄氏
      case 0xA4: // 华氏
        final t2 = _parseAsciiDouble([p.d1, p.d2, p.d3]);
        if (t2 != null) {
          targetTemp.value = t2;
          isCelsius.value = (p.id == 0x24);
        }
        break;

    // 时间设定/获取
      case 0x25: // 时间设定返回
      case 0x26: // 获取时间设定返回
        final m = _parseAsciiInt([p.d1, p.d2]);
        if (m != null) {
          targetTime.value = m;
        }
        break;

      default:
        break;
    }
  }

  // 把若干 ASCII 字节解析成 int
  int? _parseAsciiInt(List<int> bytes) {
    final s = String.fromCharCodes(bytes.where((e) => e != 0));
    if (s.isEmpty) return null;
    return int.tryParse(s);
  }

  // 把若干 ASCII 字节解析成 double
  double? _parseAsciiDouble(List<int> bytes) {
    final s = String.fromCharCodes(bytes.where((e) => e != 0));
    if (s.isEmpty) return null;
    return double.tryParse(s);
  }

  /// 解析当前温度 / 状态（ID = 0x02）
  ///
  /// 设备上报例如 "520" 表示 52.0°C：
  /// 1. 用 d1/d2/d3 三个字节组合字符串
  /// 2. 解析为数字
  /// 3. 除以 10 得到真实温度（°C）
  void _parseTempPacket(ProtocolPacket p) {
    final bytes = [p.d1, p.d2, p.d3].where((e) => e != 0).toList();
    if (bytes.isEmpty) return;

    final s = String.fromCharCodes(bytes);
    final raw = double.tryParse(s);
    if (raw == null) return;

    final realTempC = raw / 10.0; // 520 -> 52.0°C（内部统一用摄氏）

    currentTemp.value = realTempC;

    // 更新温度历史（最近 60 秒，仍然记录摄氏）
    final now = DateTime.now();
    tempHistory.add(TempPoint(now, realTempC));

    if (tempHistory.length > 60) {
      tempHistory.removeAt(0);
    }

    print('🌡 [DM] 当前温度 = $realTempC °C(内部), 历史点数=${tempHistory.length}');
  }

  // ================================
  // 对外控制方法（UI 调用这些，而不是直接碰 BLE）
  // ================================
  Future<void> togglePower() async {
    final next = !powerOn.value;
    powerOn.value = next;
    if (next) {
      await ble.cmdPowerOn();
    } else {
      await ble.cmdPowerOff();
    }
  }

  Future<void> setPower(bool on) async {
    if (powerOn.value == on) return;
    await togglePower();
  }

  Future<void> toggleInnerLight() async {
    final next = !innerLight.value;
    innerLight.value = next;
    await ble.cmdInnerLight(next);
  }

  Future<void> toggleOuterLight() async {
    final next = !outerLight.value;
    outerLight.value = next;
    await ble.cmdOuterLight(next);
  }

  Future<void> toggleColorLight() async {
    final next = !colorLight.value;
    colorLight.value = next;
    await ble.cmdColorLight(next);
  }

  Future<void> toggleOzone() async {
    final next = !ozone.value;
    ozone.value = next;
    await ble.cmdOzone(next);
  }

  Future<void> toggleAnion() async {
    final next = !anion.value;
    anion.value = next;
    await ble.cmdAnion(next);
  }

  Future<void> toggleRedLight() async {
    final next = !redLight.value;
    redLight.value = next;
    await ble.cmdRedLight(next);
  }

  /// 设置目标温度（根据 isCelsius 决定发 0x22 还是 0x23）
  Future<void> setTargetTemp(double value) async {
    if (isCelsius.value) {
      final c = clampC(value);
      targetTemp.value = c;
      await ble.cmdSetTempC(c.round());
    } else {
      final f = clampF(value);
      targetTemp.value = f;
      // ⭐ 需要在 BLE 服务中实现 cmdSetTempF
      await ble.cmdSetTempF(f.round());
    }
  }

  Future<void> setTargetTime(int minutes) async {
    targetTime.value = minutes;
    await ble.cmdSetTimeMin(minutes);
  }

  Future<void> queryHeartRate() async {
    await ble.cmdQueryHeartRate();
  }

  // ================================
  // 单位切换（真正让设备进 C/F 模式）
  // ================================

  /// 切到摄氏模式：
  /// 1. 如果当前已是 °C：只更新 isCelsius = true
  /// 2. 如果当前是 °F：把 targetTemp 从 F 转成 C，并发 0x22
  Future<void> switchToCelsiusMode() async {
    try {
      // 先让设备回一发 0x24/0xA4，防止状态不同步
      await ble.cmdQueryTargetTemp();
    } catch (_) {}

    if (isCelsius.value) {
      // 已是摄氏，只保证 UI 状态正确
      isCelsius.value = true;
      return;
    }

    // 当前 targetTemp 是华氏 → 转成摄氏
    final double f = targetTemp.value;
    double c = _fToC(f);
    c = clampC(c);

    isCelsius.value = true;
    targetTemp.value = c;

    // 发 0x22 设定摄氏温度
    await ble.cmdSetTempC(c.round());

    // 再查一发 0x24，和设备确认一下
    try {
      await ble.cmdQueryTargetTemp();
    } catch (_) {}
  }

  /// 切到华氏模式：
  /// 1. 如果当前已是 °F：只更新 isCelsius = false
  /// 2. 如果当前是 °C：把 targetTemp 从 C 转成 F，并发 0x23
  Future<void> switchToFahrenheitMode() async {
    try {
      await ble.cmdQueryTargetTemp();
    } catch (_) {}

    if (!isCelsius.value) {
      isCelsius.value = false;
      return;
    }

    // 当前 targetTemp 是摄氏 → 转成华氏
    final double c = targetTemp.value;
    double f = _cToF(c);
    f = clampF(f);

    isCelsius.value = false;
    targetTemp.value = f;

    // 发 0x23 设定华氏温度（需要在 BLE 服务实现 cmdSetTempF）
    await ble.cmdSetTempF(f.round());

    try {
      await ble.cmdQueryTargetTemp();
    } catch (_) {}
  }

  // ================================
  // 温度轮询（心跳）
  // ================================
  void _startTempTimer() {
    _stopTempTimer(); // 防止重复

    _tempTimer = Timer.periodic(const Duration(seconds: 1), (_) {
      if (connectedId.value.isNotEmpty) {
        // 每秒发一次“查询当前温度与状态”命令
        ble.cmdQueryTempAndState();
      }
    });

    print('⏱ [DM] 温度轮询心跳已启动');
  }

  void _stopTempTimer() {
    if (_tempTimer != null) {
      _tempTimer!.cancel();
      _tempTimer = null;
      print('⏹ [DM] 温度轮询心跳已停止');
    }
  }

  // ================================
  // 销毁
  // ================================
  @override
  void onClose() {
    print('♻️ [DM] 控制器销毁 → 清理 BLE 流 & 定时器');
    _pktSub?.cancel();
    _stopTempTimer();
    ble.dispose();
    super.onClose();
  }


  // ======================================================
// ⭐ 新增：设置负离子工作时间（ID=0x10）
// ======================================================
  Future<void> setAnionWorkMinutes(int minutes) async {
    final m = minutes.clamp(0, 30);
    await ble.cmdSetAnionTimeMin(m);
  }


}
